from sys import exit
from time import sleep

import pygame

from pygame.constants import USEREVENT
from settings import *
from hero import *
from enemy import *
from bullet import *
from supply import *

pygame.init()


class PlaneGame(object):

    def __init__(self):
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        pygame.display.set_caption("飞机大战")
        self.background = pygame.image.load(FILE_PATH + "image/background.png")
        self.clock_ = pygame.time.Clock()
        pygame.time.set_timer(self.SUPPLY_NOTICE_TIME, 30 * 1000)
        sleep(0.5)
        pygame.time.set_timer(self.SUPPLY_TIME, 30 * 1000)
        self.__createEvent()

    def startGame(self):
        pygame.mixer.music.play(-1)
        while True:
            # self.background = pygame.image.load(FILE_PATH + "image/background.png").convert()
            self.screen.blit(self.background, (0, 0))
            self.screen.blit(self.paused_image, self.paused_rect)
            self.__handleEvent()
            if self.life_num and not self.paused:
                self.clock_.tick(FPS)
                self.__drawEvents()
                self.__checkCollide()
            pygame.display.update()
            if self.life_num == 0:
                pygame.mixer.music.stop()
                pygame.mixer.stop()
                pygame.time.set_timer(self.SUPPLY_TIME, 0)
                print("Game Over!")

                if not self.recording:
                    self.recording = True
                    with open("record.txt", "r") as f:
                        record_score = int(f.read())
                    if self.score > record_score:
                        with open("record.txt", "w") as f:
                            f.write(str(self.score))
                    exit()

    screen = pygame.display.set_mode(SCREEN_RECT.size)
    pygame.display.set_caption("飞机大战")
    switch_image = True
    delay = 500
    e1_destroy_index = 0
    e2_destroy_index = 0
    e3_destroy_index = 0
    me_destroy_index = 0
    bullet1 = []
    bullet1_index = 0
    BULLET1_NUM = 4
    bullet2 = []
    bullet2_index = 0
    BULLET2_NUM = 8
    BLACK = (0, 0, 0)
    GREEN = (0, 255, 0)
    RED = (255, 0, 0)
    WHITE = (255, 255, 255)
    score = 0
    score_font = pygame.font.SysFont("Freestyle Script", 36)
    paused = False
    pause_nor = pygame.image.load(FILE_PATH + "image/pause_nor.png").convert_alpha()
    pause_pressed = pygame.image.load(FILE_PATH + "image/pause_pressed.png").convert_alpha()
    resume_nor = pygame.image.load(FILE_PATH + "image/resume_nor.png").convert_alpha()
    resume_pressed = pygame.image.load(FILE_PATH + "image/resume_pressed.png").convert_alpha()
    paused_rect = pause_nor.get_rect()
    paused_rect.left, paused_rect.top = SCREEN_RECT.width - paused_rect.width - 10, 10
    paused_image = pause_nor
    level = 1
    bomb = pygame.image.load(FILE_PATH + "image/bomb.png").convert_alpha()
    bomb_rect = bomb.get_rect()
    bomb_font = pygame.font.SysFont("Freestyle Script", 48)
    bomb_num = 3
    bomb_max = 3
    bullet_supply = BulletSupply()
    bomb_supply = BombSupply()
    life_supply = LifeSupply()
    SUPPLY_TIME = USEREVENT + 1
    SUPER_BULLET = USEREVENT + 2
    is_super_bullet = False
    super_bullet_s = 18
    life_num = 3
    life_image = pygame.image.load(FILE_PATH + "image/life.png").convert_alpha()
    life_rect = life_image.get_rect()
    INVINCIBLE_TIME = USEREVENT + 3
    recording = False
    SUPPLY_NOTICE_TIME = USEREVENT + 4
    supply_notice_font = pygame.font.SysFont("Freestyle Script", 48)
    supply_notice = False
    supply_notice_end = False

    pygame.mixer.init()
    pygame.mixer.music.load(FILE_PATH + "sound/game_music.mp3")
    pygame.mixer.music.set_volume(0.2)
    bullet_sound = pygame.mixer.Sound(FILE_PATH + "sound/bullet.mp3")
    bullet_sound.set_volume(0.2)
    bomb_sound = pygame.mixer.Sound(FILE_PATH + "sound/use_bomb.mp3")
    bomb_sound.set_volume(0.2)
    supply_sound = pygame.mixer.Sound(FILE_PATH + "sound/out_porp.mp3")
    supply_sound.set_volume(0.2)
    get_bomb_sound = pygame.mixer.Sound(FILE_PATH + "sound/get_bomb.mp3")
    get_bomb_sound.set_volume(0.2)
    get_bullet_sound = pygame.mixer.Sound(FILE_PATH + "sound/bullet.mp3")
    get_bullet_sound.set_volume(0.2)
    double_sound = pygame.mixer.Sound(FILE_PATH + "sound/get_double_laser.mp3")
    double_sound.set_volume(0.2)
    enemy3_fly_sound = pygame.mixer.Sound(FILE_PATH + "sound/big_spaceship_flying.mp3")
    enemy3_fly_sound.set_volume(0.2)
    enemy1_down_sound = pygame.mixer.Sound(FILE_PATH + "sound/enemy0_down.mp3")
    enemy1_down_sound.set_volume(0.2)
    enemy2_down_sound = pygame.mixer.Sound(FILE_PATH + "sound/enemy1_down.mp3")
    enemy2_down_sound.set_volume(0.2)
    enemy3_down_sound = pygame.mixer.Sound(FILE_PATH + "sound/enemy2_down.mp3")
    enemy3_down_sound.set_volume(0.2)
    me_down_sound = pygame.mixer.Sound(FILE_PATH + "sound/game_over.mp3")
    me_down_sound.set_volume(0.2)
    upgrade_sound = pygame.mixer.Sound(FILE_PATH + "sound/achievement.mp3")
    upgrade_sound.set_volume(0.2)

    # switch_image = True
    # delay = 500
    # e1_destroy_index = 0
    # e2_destroy_index = 0
    # e3_destroy_index = 0
    # me_destroy_index = 0
    # bullet1 = []
    # bullet1_index = 0
    # BULLET1_NUM = 4
    # BLACK = (0, 0, 0)
    # GREEN = (0, 255, 0)
    # RED = (255, 0, 0)
    # WHITE = (255, 255, 255)
    # score = 0
    # score_font = pygame.font.Font(FILE_PATH + "font/Marker_Felt.ttf", 36)
    # paused = False
    # pause_nor = pygame.image.load(FILE_PATH + "image/pause_nor.png").convert_alpha()
    # pause_pressed = pygame.image.load(FILE_PATH + "image/pause_pressed.png").convert_alpha()
    # resume_nor = pygame.image.load(FILE_PATH + "image/resume_nor.png").convert_alpha()
    # resume_pressed = pygame.image.load(FILE_PATH + "image/resume_pressed.png").convert_alpha()
    # paused_rect = pause_nor.get_rect()
    # paused_rect.left, paused_rect.top = SCREEN_RECT.width - paused_rect.width - 10, 10
    # paused_image = pause_nor

    def __createEvent(self):

        self.hero = Hero()
        self.hero_group = pygame.sprite.Group(self.hero)

        for i in range(self.BULLET1_NUM):
            self.bullet1.append(Bullet1(self.hero.rect.midtop))
            del i
        for i in range(self.BULLET2_NUM//2):
            self.bullet2.append(Bullet2((self.hero.rect.centerx-33, self.hero.rect.centery)))
            self.bullet2.append(Bullet2((self.hero.rect.centerx+30, self.hero.rect.centery)))

        self.enemies = pygame.sprite.Group()

        self.small_enemy_group = pygame.sprite.Group()
        self.__add_small_enemy(self.small_enemy_group, self.enemies, 15)
        self.mid_enemy_group = pygame.sprite.Group()
        self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 4)
        self.big_enemy_group = pygame.sprite.Group()
        self.__add_big_enemy(self.big_enemy_group, self.enemies, 2)

    @staticmethod
    def __add_small_enemy(group1, group2, num):
        for i in range(num):
            m0 = SmallEnemy()
            group1.add(m0)
            group2.add(m0)
        del i

    @staticmethod
    def __add_mid_enemy(group1, group2, num):
        for i in range(num):
            m1 = MidEnemy()
            group1.add(m1)
            group2.add(m1)
        del i

    @staticmethod
    def __add_big_enemy(group1, group2, num):
        for i in range(num):
            m2 = BigEnemy()
            group1.add(m2)
            group2.add(m2)
        del i

    @staticmethod
    def __inc_speed(target, inc=1):
        for i in target:
            i.speed += inc

    def __handleEvent(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()

            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1 and self.paused_rect.collidepoint(event.pos):
                    self.paused = not self.paused
                    if self.paused:
                        pygame.time.set_timer(self.SUPPLY_TIME, 0)
                        pygame.time.set_timer(self.SUPPLY_NOTICE_TIME, 0)
                        pygame.mixer.music.pause()
                        pygame.mixer.pause()
                    else:
                        pygame.time.set_timer(self.SUPPLY_NOTICE_TIME, 30 * 1000)
                        sleep(0.5)
                        pygame.time.set_timer(self.SUPPLY_TIME, 30 * 1000)
                        pygame.mixer.music.unpause()
                        pygame.mixer.unpause()

            if event.type == pygame.MOUSEMOTION:
                if self.paused_rect.collidepoint(event.pos):
                    if self.paused:
                        self.paused_image = self.resume_pressed
                    else:
                        self.paused_image = self.pause_pressed
                else:
                    if self.paused:
                        self.paused_image = self.resume_nor
                    else:
                        self.paused_image = self.pause_nor

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    if self.bomb_num:
                        self.bomb_num -= 1
                        self.bomb_sound.play()
                        for each in self.enemies:
                            if each.rect.bottom > 0:
                                each.active = False

            if event.type == self.SUPPLY_TIME:
                self.supply_sound.play()
                self.supply_notice_end = True
                self.supply_type = choice([1, 2, 3])
                if self.supply_type == 1:
                    self.bomb_supply.reset()
                elif self.supply_type == 2:
                    self.bullet_supply.reset()
                else:
                    if self.life_num < 3:
                        self.life_supply.reset()
                    else:
                        if choice([True, False]):
                            self.bomb_supply.reset()
                        else:
                            self.bullet_supply.reset()
                self.supply_notice = False
                self.supply_notice_end = False

            if event.type == self.SUPER_BULLET:
                self.is_super_bullet = False
                pygame.time.set_timer(self.SUPER_BULLET, 0)

            if event.type == self.INVINCIBLE_TIME:
                self.hero.invincible = False
                pygame.time.set_timer(self.INVINCIBLE_TIME, 0)

            if event.type == self.SUPPLY_NOTICE_TIME:
                self.supply_notice = True

        if self.level == 1 and self.score >= 50:
            self.level = 2
            self.upgrade_sound.play()
            self.bomb_max += 2
            # add 3 small enemy, 2 mid enemy and 1 big enemy
            self.__add_small_enemy(self.small_enemy_group, self.enemies, 3)
            self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 2)
            self.__add_big_enemy(self.big_enemy_group, self.enemies, 1)
            # 小型敌机的速度 + 1
            self.__inc_speed(self.small_enemy_group)
        elif self.level == 2 and self.score >= 300:
            self.level = 3
            self.upgrade_sound.play()
            self.super_bullet_s += 2
            self.bomb_max += 1
            # add 5 small enemy, 3 mid enemy and 2 big enemy
            self.__add_small_enemy(self.small_enemy_group, self.enemies, 5)
            self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 3)
            self.__add_big_enemy(self.big_enemy_group, self.enemies, 2)
            # 小型敌机的速度 + 1
            self.__inc_speed(self.small_enemy_group)
            # 中型敌机的速度 + 1
            self.__inc_speed(self.mid_enemy_group)
        elif self.level == 3 and self.score >= 600:
            self.level = 4
            self.upgrade_sound.play()
            self.super_bullet_s += 3
            self.bomb_max += 1
            # add 5 small enemy, 3 mid enemy and 2 big enemy
            self.__add_small_enemy(self.small_enemy_group, self.enemies, 5)
            self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 3)
            self.__add_big_enemy(self.big_enemy_group, self.enemies, 2)
            # 小型敌机的速度 + 1
            self.__inc_speed(self.small_enemy_group)
            # 中型敌机的速度 + 1
            self.__inc_speed(self.mid_enemy_group)
        elif self.level == 4 and self.score >= 1000:
            self.level = 5
            self.upgrade_sound.play()
            self.super_bullet_s += 4
            self.bomb_max += 1
            # add 5 small enemy, 3 mid enemy and 2 big enemy
            self.__add_small_enemy(self.small_enemy_group, self.enemies, 5)
            self.__add_mid_enemy(self.mid_enemy_group, self.enemies, 3)
            self.__add_big_enemy(self.big_enemy_group, self.enemies, 2)
            # 小型敌机的速度 + 1
            self.__inc_speed(self.small_enemy_group)
            # 中型敌机的速度 + 1
            self.__inc_speed(self.mid_enemy_group)
            # 大型敌机的速度 + 1
            # self.__inc_speed(self.big_enemy_group)

        keys_pressed = pygame.key.get_pressed()
        if keys_pressed[pygame.K_w] or keys_pressed[pygame.K_UP]:
            self.hero.moveUp()
        if keys_pressed[pygame.K_s] or keys_pressed[pygame.K_DOWN]:
            self.hero.moveDown()
        if keys_pressed[pygame.K_a] or keys_pressed[pygame.K_LEFT]:
            self.hero.moveLeft()
        if keys_pressed[pygame.K_d] or keys_pressed[pygame.K_RIGHT]:
            self.hero.moveRight()

        if self.bomb_supply.active:
            self.bomb_supply.move()
            self.screen.blit(self.bomb_supply.image, self.bomb_supply.rect)
            if pygame.sprite.collide_mask(self.bomb_supply, self.hero):
                self.get_bomb_sound.play()
                if self.bomb_num < self.bomb_max:
                    self.bomb_num += 1
                    self.bomb_supply.active = False

        if self.bullet_supply.active:
            self.bullet_supply.move()
            self.screen.blit(self.bullet_supply.image, self.bullet_supply.rect)
            if pygame.sprite.collide_mask(self.bullet_supply, self.hero):
                self.get_bullet_sound.play()
                pygame.time.set_timer(self.SUPER_BULLET, self.super_bullet_s * 1000)
                self.is_super_bullet = True
                self.bullet_supply.active = False

        if self.life_supply.active:
            self.life_supply.move()
            self.screen.blit(self.life_supply.image, self.life_supply.rect)
            if pygame.sprite.collide_mask(self.life_supply, self.hero):
                self.get_bomb_sound.play()
                if self.life_num < 3:
                    self.life_num += 1
                    self.life_supply.active = False

    def __checkCollide(self):
        self.enemies_down = pygame.sprite.spritecollide(self.hero, self.enemies, False,pygame.sprite.collide_mask)
        if self.enemies_down and not self.hero.invincible:
            self.hero.active = False
            self.is_super_bullet = False
            for e in self.enemies_down:
                e.active = False

        for b in self.bullets:
            if b.active:
                b.move()
                self.screen.blit(b.image, b.rect)
                enemy_hit = pygame.sprite.spritecollide(b, self.enemies, False, pygame.sprite.collide_mask)
                if enemy_hit:
                    b.active = False
                    for e in enemy_hit:
                        if e not in self.small_enemy_group:
                            e.hit = True
                            e.hp -= 1
                            if e.hp == 0:
                                e.active = False
                        else:
                            e.active = False

    def __drawEvents(self):
        # self.screen.blit(self.background, (0, 0))

        if not (self.delay % 10):
            self.bullet_sound.play()
            if self.is_super_bullet:
                self.bullets = self.bullet2
                self.bullets[self.bullet2_index].reset((self.hero.rect.centerx-33, self.hero.rect.centery-5))
                self.bullets[self.bullet2_index+1].reset((self.hero.rect.centerx+30, self.hero.rect.centery-5))
                self.bullet2_index = (self.bullet2_index + 2) % self.BULLET2_NUM
            else:
                self.bullets = self.bullet1
                self.bullets[self.bullet1_index].reset(self.hero.rect.midtop)
                self.bullet1_index = (self.bullet1_index + 1) % self.BULLET1_NUM

        for each in self.big_enemy_group:
            if each.active:
                each.move()
                if each.hit:
                    self.screen.blit(each.image_hit, each.rect)
                    each.hit = False
                else:
                    if self.switch_image:
                        self.screen.blit(each.image, each.rect)
                    else:
                        self.screen.blit(each.image2, each.rect)

                if each.hp != 20:
                    pygame.draw.line(self.screen, self.BLACK,
                                     (each.rect.left, each.rect.top - 5),
                                     (each.rect.right, each.rect.top - 5), 2)

                    hp_remain = each.hp / BigEnemy.hp
                    if hp_remain > 0.2:
                        hp_color = self.GREEN
                    else:
                        hp_color = self.RED
                    pygame.draw.line(self.screen, hp_color,
                                     (each.rect.left, each.rect.top - 5),
                                     (each.rect.left + each.rect.width * hp_remain, each.rect.top - 5), 2)

                    if each.rect.bottom == -50:
                        self.enemy3_fly_sound.play(-1)
            else:
                # 毁灭
                if not(self.delay % 5):
                    if not self.e3_destroy_index:
                        self.enemy3_down_sound.play()
                    self.screen.blit(each.destroy_images[self.e3_destroy_index], each.rect)
                    self.e3_destroy_index = (self.e3_destroy_index + 1) % 6
                    if not self.e3_destroy_index:
                        self.enemy3_fly_sound.stop()
                        self.score += 10
                        each.reset()
        for each in self.mid_enemy_group:
            if each.active:
                if each.hit:
                    self.screen.blit(each.image_hit, each.rect)
                    each.hit = False
                else:
                    each.move()
                    self.screen.blit(each.image, each.rect)
                if each.hp != 8:
                    pygame.draw.line(self.screen, self.BLACK,
                                     (each.rect.left, each.rect.top - 5),
                                     (each.rect.right, each.rect.top - 5),
                                     2)

                    hp_remain = each.hp / MidEnemy.hp
                    if hp_remain > 0.2:
                        hp_color = self.GREEN
                    else:
                        hp_color = self.RED
                    pygame.draw.line(self.screen, hp_color,
                                     (each.rect.left, each.rect.top - 5),
                                     (each.rect.left + each.rect.width * hp_remain, each.rect.top - 5),
                                     2)

            else:
                # 毁灭
                if not(self.delay % 5):
                    if not self.e2_destroy_index:
                        self.enemy2_down_sound.play()
                    self.screen.blit(each.destroy_images[self.e2_destroy_index], each.rect)
                    self.e2_destroy_index = (self.e2_destroy_index + 1) % 4
                    if not self.e2_destroy_index:
                        self.score += 4
                        each.reset()
        for each in self.small_enemy_group:
            if each.active:
                each.move()
                self.screen.blit(each.image, each.rect)
            else:
                # 毁灭
                if not(self.delay % 5):
                    if not self.e1_destroy_index:
                        self.enemy1_down_sound.play()
                    self.screen.blit(each.destroy_images[self.e1_destroy_index], each.rect)
                    self.e1_destroy_index = (self.e1_destroy_index + 1) % 4
                    if not self.e1_destroy_index:
                        self.score += 1
                        each.reset()
        if self.hero.active:
            if self.switch_image:
                self.screen.blit(self.hero.image, self.hero.rect)
            else:
                self.screen.blit(self.hero.image2, self.hero.rect)
        else:
            # 毁灭
            if not(self.delay % 5):
                if not self.me_destroy_index:
                    self.me_down_sound.play()
                self.screen.blit(self.hero.destroy_images[self.me_destroy_index], each.rect)
                self.me_destroy_index = (self.me_destroy_index + 1) % 4
                if not self.me_destroy_index:
                    self.life_num -= 1
                    self.hero.reset()
                    pygame.time.set_timer(self.INVINCIBLE_TIME, 3 * 1000)

        self.score_text = self.score_font.render("Score : {}".format(self.score), True, self.WHITE)
        self.screen.blit(self.score_text, (10, 5))

        self.screen.blit(self.paused_image, self.paused_rect)

        self.bomb_text = self.bomb_font.render("{} / {}".format(self.bomb_num, self.bomb_max), True, self.WHITE)
        self.text_rect = self.bomb_text.get_rect()
        self.screen.blit(self.bomb, (10, SCREEN_RECT.height - 10 - self.bomb_rect.height))
        self.screen.blit(self.bomb_text, (20 + self.bomb_rect.width, SCREEN_RECT.height - 5 - self.text_rect.height))

        if self.life_num:
            for i in range(self.life_num):
                self.screen.blit(self.life_image,
                                 (SCREEN_RECT.width-50-(i*1)*self.life_rect.width,
                                  SCREEN_RECT.height-10-self.life_rect.height))

        if self.supply_notice and not self.supply_notice_end:
            self.supply_notice_text = self.supply_notice_font.render("supply time!", True, self.WHITE)
            self.screen.blit(self.supply_notice_text, (SCREEN_RECT.centerx - 40, 0))

        if not (self.delay % 5):
            self.switch_image = not self.switch_image
        self.delay -= 1
        if not self.delay:
            self.delay = 500


if __name__ == "__main__":
    game = PlaneGame()
    print("这里是游戏后台")
    try:
        game.startGame()
    except SystemExit:
        pass
    except Exception as problem:
        print("未知错误：{}".format(problem))
